﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
using System;
using System.Collections.Generic;
using System.Threading;
using System.Reflection;
using BrainTechLLC.ThreadSafeObjects;

namespace BrainTechLLC
{
    public static class Populate
    {     
        /// <summary>
        /// If item is null, uses Interlocked.CompareExchange to atomically assign the item a new value (new T())
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="item"></param>
        /// <returns></returns>
        public static T CreateIfNull<T>(ref T item) where T : class, new()
        {
            if (item == null) { Interlocked.CompareExchange<T>(ref item, new T(), null); }
            return item;
        }

        /// <summary>
        /// If item is null, uses Interlocked.CompareExchange to atomically assign the item a new value
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="item"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public static T CreateIfNull<T>(ref T item, T value) where T : class
        {
            if (item == null) { Interlocked.CompareExchange<T>(ref item, value, null); }
            return item;
        }

        /// <summary>
        /// If interface or parent item is null, uses Interlocked.CompareExchange to atomically assign the item a new value (new TClass())
        /// </summary>
        /// <typeparam name="TInterface"></typeparam>
        /// <typeparam name="TClass"></typeparam>
        /// <param name="item"></param>
        /// <returns></returns>
        public static TInterface CreateIfNull<TInterface, TClass>(ref TInterface item)
            where TInterface : class
            where TClass : class, TInterface, new()
        {
            if (item == null) { Interlocked.CompareExchange<TInterface>(ref item, new TClass(), null); }
            return item;
        }

        /// <summary>
        /// If item is null, uses Interlocked.CompareExchange to atomically assign the item a new value (new T())
        /// Returns item
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="item"></param>
        /// <returns></returns>
        public static T OnDemand<T>(ref T item) where T : class, new()
        {
            if (item == null)
            {
                Interlocked.CompareExchange<T>(ref item, new T(), null);
            }

            return item;
        }

        /// <summary>
        /// If item is null, uses Interlocked.CompareExchange to atomically assign the item a new value (return value from func())
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="item"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static T OnDemand<T>(ref T item, Func<T> func) where T : class
        {
            if (item == null)
            {
                Interlocked.CompareExchange<T>(ref item, func(), null);
            }

            return item;
        }

        /// <summary>
        /// If interface or parent item is null, uses Interlocked.CompareExchange to atomically assign the item a new value (return value from func())
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <param name="item"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static T1 OnDemand<T1, T2>(ref T1 item, Func<T2> func)
            where T1 : class
            where T2 : class
        {
            if (item == null)
                Interlocked.CompareExchange<T1>(ref item, func() as T1, null);

            return item;
        }

        /// <summary>
        /// If interface or parent item is null, uses Interlocked.CompareExchange to atomically assign the item a new value (new T2() as T1)
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <typeparam name="T2"></typeparam>
        /// <param name="item"></param>
        /// <returns></returns>
        public static T1 OnDemand<T1, T2>(ref T1 item)
            where T1 : class
            where T2 : class, new()
        {
            if (item == null)
                Interlocked.CompareExchange<T1>(ref item, new T2() as T1, null);

            return item;
        }

        /// <summary>
        /// If value.Equals(varToCheck) then assign varToCheck the result of del()
        /// returns varToCheck
        /// </summary>
        /// <typeparam name="T1"></typeparam>
        /// <param name="value"></param>
        /// <param name="varToCheck"></param>
        /// <param name="del"></param>
        /// <returns></returns>
        public static T1 PopulateIf<T1>(this T1 value, ref T1 varToCheck, Func<T1> del)
        {
            if (value.Equals(varToCheck))
            {
                varToCheck = del();
            }
            
            return varToCheck;
        }        
    }
}